#pragma once
#include "IOContainer.h"
#include "IOObject.h"
#include "Socket.h"
#include <afxsock.h>
class CTCPException:public CException
{
	//DECLARE_DYNAMIC(CTCPException);

};

//IMPLEMENT_DYNAMIC(CTCPException,CException)
class CTCPObject:public IOFrame::CIOObject
{
public:
	CTCPObject(IOFrame::CIOContainer const*pContainer)
		:CIOObject(pContainer)
		,m_ulAddress(0u)
		,m_usPort(0u)
	{
		m_pSendData=IOFrame::NewIOData();
		m_pRecvData=IOFrame::NewIOData(50);
		ASSERT(NULL!=m_pSendData);
		ASSERT(NULL!=m_pRecvData);

		
		if(NULL==m_pSendData
			||NULL==m_pRecvData
			||!Reset())
		{
			throw new CTCPException;
		}
	}

	~CTCPObject()
	{
		DeleteIOData(m_pRecvData);
		DeleteIOData(m_pSendData);
	}
	BOOL Reset()
	{
		ResetData(m_pSendData);
		ResetData(m_pRecvData);
		m_pSendData->dwDataType|=IOFrame::IOBIT_SEND|IOFrame::IOBIT_CONNECT;
		m_pRecvData->dwDataType|=IOFrame::IOBIT_RECV;
		BOOL bSuccessCreateSocket=m_Sock.CreateSocket();


		ASSERT(TRUE==bSuccessCreateSocket);
		return bSuccessCreateSocket;
	}
protected:
	virtual BOOL OnSendComplete()
	{
		return FALSE;
	}

	virtual BOOL OnRecvComplete()
	{
		return FALSE;
	}

	virtual BOOL OnRecv(LPVOID lpBuffer,DWORD dwLen)
	{
		return FALSE;
	}

	virtual BOOL Begin()
	{
		ASSERT(0u!=m_ulAddress);
		ASSERT(0u!=m_usPort);
		m_Sock.Bind();
		if(UpdateSendData())
		{
			m_Sock.ConnectEx(m_ulAddress,m_usPort
				,&m_pSendData->ol
				,m_pSendData->buf
				,m_pSendData->dwBufferLen);
		}
		else
		{
			m_Sock.ConnectEx(m_ulAddress,m_usPort
				,&m_pSendData->ol);
		}
		return TRUE;
	}

	virtual BOOL Perform(IOFrame::PIOData pData)
	{
		if(pData->dwDataType&IOFrame::IOBIT_SEND)
		{
			if(UpdateSendData())
			{
				WSABUF wsaBuf;
				wsaBuf.buf=(char *)m_pSendData->buf;
				wsaBuf.len=m_pSendData->dwBufferLen;
				m_Sock.SendEx(&wsaBuf,1,&m_pSendData->ol);
			}
			else if(OnSendComplete()
				&&UpdateSendData())
			{
				WSABUF wsaBuf;
				wsaBuf.buf=(char *)m_pSendData->buf;
				wsaBuf.len=m_pSendData->dwBufferLen;
				m_Sock.SendEx(&wsaBuf,1,&m_pSendData->ol);
			}
		}

		if(pData->dwDataType&IOFrame::IOBIT_CONNECT)
		{
			pData->dwDataType&=~IOFrame::IOBIT_CONNECT;
			WSABUF wsaBuf;
			wsaBuf.buf=(char *)m_pRecvData->buf;
			wsaBuf.len=m_pRecvData->dwBufSize;
			m_Sock.RecvEx(&wsaBuf,1,&m_pRecvData->ol);
		}

		if(pData->dwDataType&IOFrame::IOBIT_RECV)
		{
			if(OnRecv(pData->buf,pData->dwBufferLen))
			{
				WSABUF wsaBuf;
				wsaBuf.buf=(char *)m_pRecvData->buf;
				wsaBuf.len=m_pRecvData->dwBufSize;
				m_Sock.RecvEx(&wsaBuf,1,&m_pRecvData->ol);
			}
			else
			{
				return FALSE;
			}
		}
		return TRUE;
	}

	virtual void OnError()
	{
		;
	}

	virtual void PerformError()
	{
		
		m_Sock.CloseSocket();
		OnError();
	}

	virtual BOOL Error(IOFrame::PIOData pData)
	{		
		return TRUE;
	}

	virtual HANDLE GetHandle() const
	{
		return m_Sock;
	}

public:
	void SetAddress(u_long ulAddress,u_short usPort)
	{
		m_ulAddress=ulAddress;
		m_usPort=usPort;
	}
	
	BOOL SetSendData(LPVOID lpBuffer,DWORD dwLen)
	{
		ASSERT(NULL==m_pSendData->pData);
		ASSERT(0u==m_pSendData->dwLastDataLen);
		m_pSendData->pData=LPBYTE(lpBuffer);
		m_pSendData->dwLastDataLen=dwLen;
		return TRUE;
	}

	

protected:
	BOOL UpdateSendData()
	{
		if(NULL!=m_pSendData->pData
			&&0u!=m_pSendData->dwLastDataLen)
		{
			m_pSendData->dwBufferLen=
				(m_pSendData->dwLastDataLen>m_pSendData->dwBufSize)
				?(m_pSendData->dwBufSize)
				:(m_pSendData->dwLastDataLen);
			memcpy(m_pSendData->buf,m_pSendData->pData,m_pSendData->dwBufferLen);			
			m_pSendData->pData+=m_pSendData->dwBufferLen;
			m_pSendData->dwLastDataLen-=m_pSendData->dwBufferLen;

			if(0u==m_pSendData->dwLastDataLen)
			{
				m_pSendData->pData=NULL;
			}
			return TRUE;
		}
		else
		{
			return FALSE;
		}
	}
protected:
	//friend IOFrame::CIOContainer;
	u_long m_ulAddress;
	u_short m_usPort;
	IOFrame::PIOData m_pSendData,m_pRecvData;
	CASYNCSocket m_Sock;
};
